package ch.simplix.android.geo.discoverer.gps;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;

public class GPSDiscovererService extends Service {
	/** Action being broadcasted whenever a new measurement was retrieved */
	public static final String GPS_ACTION = "ch.simplix.android.geo.discoverer.gps.GPS_DISCOVERER_SERVICE";
	private boolean wasGPSDisabled;

	// Moonblink
	// http://code.google.com/p/moonblink/source/browse/trunk/Dazzle/src/org/hermit/dazzle/LocationSettings.java

	private static boolean getGpsState(final Context context) {
		final LocationManager manager = (LocationManager) context
				.getSystemService(Context.LOCATION_SERVICE);
		return manager.isProviderEnabled(LocationManager.GPS_PROVIDER);
	}

	private static void toggleGps(final Context context) {
		final Intent intent = new Intent();
		intent.setClassName("com.android.settings",
				"com.android.settings.widget.SettingsAppWidgetProvider");
		intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
		intent.setData(Uri.parse("custom:3"));
		context.sendBroadcast(intent);
	}

	/**
	 * Toggle the current state.
	 * 
	 * @param context
	 *            The context we're running in.
	 */
	private static void toggle(final Context context) {
		try {
			toggleGps(context);
		} catch (Exception e) {
			Intent gpsIntent = new Intent(
					Settings.ACTION_LOCATION_SOURCE_SETTINGS);
			gpsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			context.startActivity(gpsIntent);
		}
	}

	// Moonblink

	private boolean stop = true;
	private int updateIntervalInMillis;
	private int positionChangeInMeters;
	private LocationManager locationManager;
	private LocationDiscoveryListener locationDiscoveryListener;
	private Location latestLocation;

	public GPSDiscovererService() {
		updateIntervalInMillis = 15000;
		positionChangeInMeters = 10;
	}

	@Override
	public IBinder onBind(Intent intent) {
		return binder;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		locationDiscoveryListener = new LocationDiscoveryListener();
		/* Use the LocationManager class to obtain GPS locations */
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
	}

	@Override
	public void onDestroy() {
		stopTimedRepetition();
		locationDiscoveryListener = null;
		super.onDestroy();
	}

	/**
	 * @see Binder
	 */
	public class LocalBinder extends Binder {
		public GPSDiscovererService getService() {
			return GPSDiscovererService.this;
		}
	}

	/**
	 * Start scanning immediately
	 */
	public void startTimedRepetition() {
		if (!stop)
			return;
		stop = false;
		if (!GPSDiscovererService.getGpsState(this)) {
			this.wasGPSDisabled = true;
			GPSDiscovererService.toggle(this);
		}

		Location location = locationManager
				.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		if (location != null && !location.equals(this.latestLocation)) {
			this.latestLocation = location;
		}

		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
				updateIntervalInMillis, positionChangeInMeters,
				locationDiscoveryListener);
	}

	public void stopTimedRepetition() {
		if (stop)
			return;
		if (wasGPSDisabled) {
			if (GPSDiscovererService.getGpsState(this)) {
				GPSDiscovererService.toggle(this);
			}
		}
		stop = true;
		if (locationManager != null && locationDiscoveryListener != null)
			locationManager.removeUpdates(locationDiscoveryListener);
	}

	@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);
		boolean startDiscover = intent.getExtras().getBoolean("start");
		if (startDiscover) {
			Log.d("GPS", "onStart");
			startTimedRepetition();
		}
		boolean stop = intent.getExtras().getBoolean("stop");
		if (stop) {
			this.stopTimedRepetition();
		}
	}

	/**
	 * Returns the latest location from the scan.
	 * 
	 * @return
	 */
	public Location getLatestLocation() {
		return latestLocation;
	}

	private final LocalBinder binder = new LocalBinder();

	class LocationDiscoveryListener implements LocationListener {

		@Override
		public void onLocationChanged(Location location) {
			latestLocation = location;
			Intent gpsIntent = new Intent(GPS_ACTION);
			sendBroadcast(gpsIntent);
			if (stop) {
				if (locationManager != null
						&& locationDiscoveryListener != null)
					locationManager.removeUpdates(locationDiscoveryListener);
			}

		}

		@Override
		public void onProviderDisabled(String provider) {
			if (stop) {
				if (locationManager != null
						&& locationDiscoveryListener != null)
					locationManager.removeUpdates(locationDiscoveryListener);
				return;
			}

		}

		@Override
		public void onProviderEnabled(String provider) {
			if (stop) {
				if (locationManager != null
						&& locationDiscoveryListener != null)
					locationManager.removeUpdates(locationDiscoveryListener);
				return;
			}

		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			if (stop) {
				if (locationManager != null
						&& locationDiscoveryListener != null)
					locationManager.removeUpdates(locationDiscoveryListener);
				return;
			}

		}

	}

}
